#pragma once

#include "NetworkTypes.h"
#include <system_error>
#include <string>

namespace SeanNetwork {

/**
 * @brief Network error codes used throughout the library.
 */
enum class NetworkErrorCode {
    Success = 0,
    Unknown = 1,
    ConnectionFailed = 2,
    ConnectionClosed = 3,
    ConnectionTimeout = 4,
    MessageTooLarge = 5,
    InvalidMessage = 6,
    SendFailed = 7,
    ReceiveFailed = 8,
    InvalidState = 9,
    InvalidParameter = 10,
    ResolutionFailed = 11,
    MaxRetryAttemptsReached = 12,
    ChannelSwitchFailed = 13,
    InvalidChannelType = 14,
    SerializationFailed = 15,
    DeserializationFailed = 16,
    OperationCanceled = 17,
    BufferOverflow = 18,
    InvalidArgument = 19,
    Timeout = 20,
    NotInitialized = 21,
    AlreadyInitialized = 22,
    OutOfMemory = 23,
    InternalError = 24
};

/**
 * @brief Network error category for system_error integration.
 */
class NetworkErrorCategory : public std::error_category {
public:
	using NetworkErrorCode = SeanNetwork::NetworkErrorCode;
    const char* name() const noexcept override {
        return "SeanNetwork";
    }
    
    std::string message(int value) const override {
        NetworkErrorCode code = static_cast<NetworkErrorCode>(value);
        switch (code) {
            case NetworkErrorCode::Success:
                return "操作成功";
            case NetworkErrorCode::InvalidArgument:
                return "无效参数";
            case NetworkErrorCode::ConnectionFailed:
                return "连接失败";
            case NetworkErrorCode::ConnectionClosed:
                return "连接已关闭";
            case NetworkErrorCode::SendFailed:
                return "发送失败";
            case NetworkErrorCode::ReceiveFailed:
                return "接收失败";
            case NetworkErrorCode::Timeout:
                return "操作超时";
            case NetworkErrorCode::NotInitialized:
                return "未初始化";
            case NetworkErrorCode::AlreadyInitialized:
                return "已经初始化";
            case NetworkErrorCode::OutOfMemory:
                return "内存不足";
            case NetworkErrorCode::InternalError:
                return "内部错误";
            default:
                return "未知错误";
        }
    }
};

/**
 * @brief Get the singleton instance of the NetworkErrorCategory.
 */
inline const NetworkErrorCategory& NetworkCategory() {
    static NetworkErrorCategory instance;
    return instance;
}

/**
 * @brief Make an error_code from a NetworkErrorCode.
 */
inline std::error_code make_error_code(NetworkErrorCode code) {
    return std::error_code(static_cast<int>(code), NetworkCategory());
}

/**
 * @brief Network exception class.
 */
class NetworkException : public std::system_error {
public:
    NetworkException(NetworkErrorCode code, const std::string& details = "")
        : std::system_error(make_error_code(code)) {
        m_Details = details;
    }
    
    const std::string& details() const {
        return m_Details;
    }
    
    const char* what() const noexcept override {
        if (m_What.empty()) {
            if (m_Details.empty()) {
                m_What = std::system_error::what();
            } else {
                m_What = std::string(std::system_error::what()) + ": " + m_Details;
            }
        }
        return m_What.c_str();
    }
    
private:
    std::string m_Details;
    mutable std::string m_What;
};

/**
 * @brief Helper function to check a condition and throw if it fails.
 */
inline void ThrowIfFailed(bool condition, NetworkErrorCode code, const std::string& details = "") {
    if (!condition) {
        throw NetworkException(code, details);
    }
}

/**
 * @brief Get and format a network error message.
 */
inline std::string FormatErrorMessage(NetworkErrorCode code, const std::string& details = "") {
    std::string baseMsg = NetworkCategory().message(static_cast<int>(code));
    if (!details.empty()) {
        baseMsg += ": " + details;
    }
    return baseMsg;
}

} // namespace SeanNetwork

// Register NetworkErrorCode with std::error_code
namespace std {
    template<>
    struct is_error_code_enum<SeanNetwork::NetworkErrorCode> : true_type {};
} 
